import { AfterViewInit, Component, OnInit } from '@angular/core';
import {
  FormArray,
  FormBuilder,
  FormControl,
  FormGroup,
  ValidationErrors,
  Validators,
} from '@angular/forms';
import { Observable, of } from 'rxjs';
import { concatMap } from 'rxjs/operators';
import { TemplateService } from 'src/app/common/providers';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.less'],
})
export class FormComponent implements OnInit, AfterViewInit {
  // 响应式表单
  validateForm: FormGroup;

  constructor(private fb: FormBuilder, private templateServ: TemplateService) {
    // 初始化响应式表单
    this.validateForm = this.fb.group(
      {
        email: ['', [Validators.required, Validators.email]],
        password: ['', Validators.required],
        checkPassword: ['', [Validators.required]],
        // 昵称验证涉及异步验证，使用 FormBuilder 创建 FormControl
        nickname: this.fb.control('', {
          validators: Validators.required,
          // 避免 this 指针错误，绑定作用域
          asyncValidators: this.nicknameAsyncValidator.bind(this),
          // 修改验证触发方式为输入框失焦
          updateOn: 'blur',
        }),
        phone: [
          '',
          [
            Validators.required,
            // 自定义正则验证
            Validators.pattern(/^1[345789]\d{9}$/),
          ],
        ],
        birthday: [null],
        address: this.fb.array([], {
          // 动态表单（FormArray）地址栏数量验证
          validators: this.addressValidator,
        }),
        isAgree: [false, Validators.requiredTrue],
      },
      {
        // 跨字段验证
        validators: this.checkPasswordValidator,
      }
    );
  }

  ngOnInit(): void {
    // 初始化后，自动新增一条地址栏信息
    this.addAddress();
  }

  ngAfterViewInit(): void {
    // document.querySelector('#disabled').setAttribute('disabled', 'disabled');
  }

  /**
   * 设置地址（address）信息 getter 属性，便于在 html 和 typescript 代码中使用
   */
  get address(): FormArray {
    return this.validateForm.get('address') as FormArray;
  }

  /**
   * 自定义验证，两次输入的密码是否一致
   * @param group 响应式表单 FormGroup
   */
  checkPasswordValidator(group: FormGroup): ValidationErrors {
    // 密码控件
    const passwordControl = group.get('password') as FormControl;
    // 确认密码控件
    const checkPasswordControl = group.get('checkPassword') as FormControl;
    let result: ValidationErrors = null;
    // 判断两次输入密码是否一致，并设置不一致的验证结果
    if (passwordControl.value !== checkPasswordControl.value) {
      result = {
        checkPassword: true,
      };
    }
    console.log(checkPasswordControl);
    // 确认密码控件如果没有其他错误，则设置 checkPassword 验证结果
    if (
      checkPasswordControl.errors === null ||
      checkPasswordControl.hasError('checkPassword')
    ) {
      checkPasswordControl.setErrors(result);
    }
    return null;
  }

  /**
   * 自定义验证，地址数量验证
   * @param array 响应式表单 FormArray
   */
  addressValidator(array: FormArray): ValidationErrors {
    if (array.length > 0) {
      return null;
    } else {
      return {
        addressCount: true,
      };
    }
  }

  /**
   * 自定义异步验证，昵称是否重复验证
   * @param control 响应式表单 FormControl
   */
  nicknameAsyncValidator(control: FormControl): Observable<ValidationErrors> {
    // 请求服务端验证，并对服务端返回结果进行处理
    return this.templateServ.checkNickname(control.value).pipe(
      // 使用 concatMap 来取消上一次输入的干扰
      concatMap((res) => {
        if (res.success) {
          return of<ValidationErrors>(null);
        } else {
          return of<ValidationErrors>({
            nickname: true,
          });
        }
      })
    );
  }

  /**
   * 添加地址栏
   */
  addAddress(): void {
    if (this.address.length < 3) {
      this.address.push(this.fb.control('', Validators.required));
    }
  }

  /**
   * 移除指定下标的地址栏
   * @param index 地址栏下标
   */
  removeAddress(index: number): void {
    if (this.address.length > 1) {
      this.address.removeAt(index);
    }
  }

  reset(): void {
    this.validateForm.reset();
  }
}
